#include "ad.h"
#include "srt/srt.h"
#include "data_center/data_center.h"
#include "i2c/i2c.h"
#include "pico/stdlib.h"

#define LOG_TAG "Ad"
#include "log/log.h"

// 定义设备地址
#define AD_ADDR   0x40  ///< AD采样从设备地址

// 定义寄存器
#define REG_CONFIG     0x00  ///< 模式配置寄存器
#define REG_SHUNT_VOLT 0x01  ///< 采样电阻压差；取值：2.5uV~81.92mV(0~7FF)(10mΩ采样电阻下最大电流8A)
#define REG_BUS_VOLT   0x02  ///< BUS总线电压：1.25V~40.96V(0~7FF)
#define REG_POWER      0x03  ///< 功率：Current_LSB * 25, FSR = 0xFFFF
#define REG_CURRENT    0x04  ///< 电流：LSB = 0.02mA，FSR = 0x7FFF
#define REG_CALIB      0x05  ///< 当单位是mA时，0.02R=0xA00,0.01R=0x200)(上限：8A)，写入的数据需要根据实际电路中的采样电阻以及电流分辨率来设置
#define REG_MASK_EN    0x06
#define REG_ALERT      0x07
#define REG_MAN_ID     0xFE  ///< 0x5449
#define REG_ID         0xFF  ///< 0x2260

/**
 * TAd 采样 结构体
 */
struct TAdTag
{
    Bool   is_init_;        ///< 是否初始化
    UInt32 last_get_tick_;  ///< 上一次获取时间
    UInt32 loop_;           ///< 循环次数
};
typedef struct TAdTag TAd;

static TAd ad_ = {
    .is_init_       = False,
    .last_get_tick_ = 0,
    .loop_          = 0,
};
static TAd* self = &ad_;

static Int32 INA226_Write(UInt8 reg, UInt16 data)
{
    UInt8 send_frame[3] = {reg, data >> 8, data & 0xff};

    return TI2CSendData(AD_ADDR, send_frame, sizeof(send_frame));
}

static Int32 INA226_SelectReg(UInt8 reg)
{
    return TI2CSendData(AD_ADDR, &reg, 1);
}

static UInt16 INA226_Read(void)
{
    UInt16 ret = 0;

    TI2CReadData(AD_ADDR, (UInt8 *)&ret, sizeof(ret));

    ret = ((ret >> 8) & 0xff) | ((ret & 0xff) << 8);

    return ret;
}


/**
 * 获取电压
 *
 * @return volt 电压 0.001V
 */
UInt16 INA226_GetVoltage(void)
{
    UInt16 volt = 0;

    INA226_SelectReg(REG_BUS_VOLT);
    volt = INA226_Read();  //1.25mV/bit

    // LOG_E("volt value=0x%04X", volt);

    volt *= 1.25;

    return volt;
}

/**
 * 获取校准值
 *
 * @return 配置原始值
 */
UInt16 INA226_GetCALIB(void)
{
    UInt16 config = 0;

    INA226_SelectReg(REG_CALIB);
    config = INA226_Read();  //1.25mV/bit

    // LOG_E("calib value=0x%04x", config);

    return config;
}

/**
 * 获取电流
 *
 * @return curr 电流 0.1mA
 */
UInt16 INA226_GetCurrent(void)
{
    UInt16 curr = 0;

    INA226_SelectReg(REG_CURRENT);
    curr = INA226_Read();

    // LOG_E("curr value=0x%04X", curr);

    if ((curr & 0x8000) > 0)  ///< 最高位为1，校准电流为0
    {
        // LOG_E("target 0x%X", curr & 0x8000);
        curr = 0;
    }

    return curr;
}

static Bool ad_init(void)
{
    Int32 send_ret = 0;

    send_ret = INA226_Write(REG_CONFIG, 0x47FF);  ///< 初始化结果采用64次平均值，8.244ms总线电压转换时间，8.244ms分流电压转换时间，全功能，连续模式

    LOG_E("INA226 config ret=%d", send_ret);

    if (send_ret == PICO_ERROR_GENERIC)
    {
        LOG_W("AD device not exists");
        return False;
    }

    send_ret = INA226_Write(REG_CALIB, 0x1400);  ///< 当单位是0.1mA时，0.01R=0x1400)(上限：3.2768A)

    LOG_E("INA226 calib ret=%d", send_ret);

    return True;
}

Bool TAdInit()
{
    TDataCenterInit(kDataCenterUserAd);

    self->is_init_ = ad_init();
}

Bool TAdFini()
{
    self->is_init_ = False;

    TDataCenterFini(kDataCenterUserAd);
}

static void DealMsg(TDataCenterMsg *msg)
{
    if (msg != NULL)
    {
        LOG_D("Get Data Center msg! msg type: %d", msg->msg_type);

        switch (msg->msg_type)
        {


        default:
            LOG_W("Unknown msg type, ignore msg.");
            break;
        }
    }
}

void TAdRunOnce(UInt32 cur_ticks)
{
    if (self->is_init_)
    {
        // 消息交互
        TDataCenterMsg *msg = TDataCenterPopMsg(kDataCenterUserAd);

        if (msg != NULL)
        {
            DealMsg(msg);
            TDataCenterDestroyMsg(msg);
        }

        if (cur_ticks - self->last_get_tick_ >= 200)
        {
            Float volt_data = INA226_GetVoltage() * 0.001;
            Float curr_data = INA226_GetCurrent() * 0.1;

            if ((self->loop_ ++) % 10 == 0)
                LOG_D("volt=%f V, curr=%f mA", volt_data, curr_data);

            if (TSrtSetFloat(kSrtFloatBusVolt, volt_data) == 0)
                LOG_W("Save volt fail");

            if (TSrtSetFloat(kSrtFloatBusCurr, curr_data) == 0)
                LOG_W("Save curr fail");

            self->last_get_tick_ = cur_ticks;
        }
    }
}
